#ifndef GAMEMANAGER_H
#define GAMEMANAGER_H

#include "Game.h"
#include "UserInfo.h"
#include "GamePlatform.h"

#include "Game/SocketDefine.h"

#include "_Global/GameCommon.h"
#include "_Global/GlobalClass.h"
#include "_Global/VersionCheck/VersionCheck.h"

#include <QObject>
#include <QApplication>
#include <QJSValue>



class QQmlApplicationEngine;
class QQuickWindow;
class Sqlite;
class TcpSocket;
//class Game;
//class UserInfo;

//管理登录窗口和游戏窗口
//负责传递Socket消息
class GameManager : public QObject
{
    Q_OBJECT
    //Q_ENUMS(_ClientGroupStatus)
    Q_ENUMS(_Common::NetDBDataType)

    Q_PROPERTY(UserInfo* userInfo READ getUserInfo)
    Q_PROPERTY(Game* gameCore READ getGameCore)
    Q_PROPERTY(_Platform* platform READ getPlatform)
    //Q_PROPERTY(QObject* sqlite READ getSqliteDB)
    //Q_PROPERTY(QString platform READ platform)
    Q_PROPERTY(QVariantMap gameConfig READ getGameConfig)  //QVariantMap不用qml注册,因为它就是js中的 Object

    Q_PROPERTY(QString externalDataPath READ getExternalDataPath)   //获取外部存储目录（框架使用）



public:
    //创建登录窗口,注册窗口,大厅窗口,游戏窗口,链接信号槽
    explicit GameManager(QObject *parent = nullptr);
    virtual ~GameManager();

    bool InitOnce();


signals:
    //void s_ConnectServerErr(int errType,int errValue);

    //To QML:
    //void s_qml_GameStart();         //游戏开始
    void s_qml_GameOver(GameModel::_GameStatus status, qint32 code);    //游戏结束


    void s_qml_Message(QString msg, int level);     //游戏信息,level:0信息;1警告;2退出

    //升级信息,type:-2|-3(版本检测出错),-1(版本比服务器大出错),0(不升级),1(建议),2(强制升级)
    void s_qml_UpdateInfo(QString url, int type);


    //通知qml
    void s_qml_CreateGroup(qint32 groupID, bool success, qint16 code);
    //通知qml更新房间信息
    void s_qml_UpdateGroup(bool success, qint16 code);
    //通知qml本人关闭房间
    void s_qml_CloseGroup(bool success, qint16 code);
    //通知qml设置房主
    void s_qml_SetMaster(QObject* playerInfo, bool bMaster, bool bRunning, bool bAllDataIsEmpty, bool success, qint16 code);
    //通知qml本人加入房间
    void s_qml_JoinGroup(qint32 groupID, bool bRunning, bool success, qint16 code);
    void s_qml_ReJoinRunningGroup(qint32 socketID, qint32 oldSocketID, qint32 groupIndex, bool success, qint16 code);
    //通知qml本人退出房间
    void s_qml_ExitGroup(bool success, qint16 code);
    //通知qml准备
    void s_qml_GetReady(QObject* playerInfo, bool success, qint16 code);
    //通知qml
    void s_qml_GroupKick(bool success, qint16 code);
    //通知qml其他人加入房间
    void s_qml_OthersJoinGroup(QObject* playerInfo, bool bRunning, bool bResetFrame, bool bIn, bool bKeepGroupIndex);
    void s_qml_OthersReJoinRunningGroup(qint32 socketID, qint32 oldSocketID, qint32 groupIndex, quint32 userGameID, bool bRunning, bool bResetFrame, bool bIn);
    //准备信号
    //void s_qml_OthersReadyInGroup(QObject* playerInfo, qint16 status, qint16 duiWu);
    //聊天信息
    void s_qml_OthersMessage(quint32 userGameID, qint16 type, QString msg);


    //设置用户额外共享数据
    void s_SetClientShareExtraGameData(qint16 code, bool successed);


    void s_qml_GameDisconnected(qint32 code);



//用户数据操作
    void s_GetGameDataToNetDB(QVariantList listData, qint32 type, qint32 value, qint16 code, bool successed, QJSValue jsCallbackFunc);
    void s_SetGameDataToNetDB(qint32 type, qint32 value, qint16 code, bool successed, QJSValue jsCallbackFunc);
    void s_DeleteGameDataToNetDB(qint32 type, qint32 value, qint16 code, bool successed, QJSValue jsCallbackFunc);

    void s_InsertGameDataToNetDB(qint32 type, qint32 value, qint16 code, bool successed, QJSValue jsCallbackFunc);
    void s_UpdateGameDataToNetDB(qint32 type, qint32 value, qint16 code, bool successed, QJSValue jsCallbackFunc);


    void s_NetDBQuery(qint32 value, qint32 rowsAffected, QVariant lastInsertID, QVariantList listData, qint16 code, bool successed, QJSValue jsCallbackFunc);


//游戏操作
    void s_GameTransferData(quint32 userGameID, QVariantMap data);
    void s_GameSyncData(quint32 userGameID, QVariantMap data);
    void s_GameFrameData(quint32 frameIndex, QVariantList data);
    void s_GameSyncAllData(quint32 frameIndex, qint32 sendFrameCount, QVariantMap data, QVariantList datalist);



    //改变所有窗口visible
    //type:1(退出到登录界面);2(退出到服务器选择界面)
    //void s_qml_ChangeAllWindowVisible(int type);


    void s_qml_DebugMsg(QString msg);               //调试信息(出现在调试框)



//网络处理
public:
    //客户端socket数据处理
    //From GameCore
    void OnInfoReadyRead(TcpSocket* sock);
    void OnGameReadyRead(TcpSocket* sock);



//数据库处理
    int SaveConfigToDb(QString key, QString value); //存储数据key和value
    int DeleteConfigToDb(QString key);
    int LoadConfigFromDb();    //读取Config到Map

    //链接并读取本地数据库
    bool LoadDatabase();
    int CheckConfig();  //暂时无用!!!检查Config字段(主要是升级信息),<0出错;=0正常;>0重新连接数据库


//槽
public slots:

    //游戏开始，进行 GameInit 初始化
    //netPlay为true表示联网,否则为单机
    void sl_StartGame(bool netPlay = false, bool isStarted = false);

    //游戏结束(0表示正常结束,不需要释放Game;其他值表示需要释放)
    //From GameCore
    void sl_GameOver(GameModel::_GameStatus status, qint32 code);


//其他功能请求
public slots:
    //增加设置项
    void sl_qml_SetGameConfig(QString k, QVariant v)
    {
        m_mapGameConfig.insert(k, v);
    }
    //存储设置项
    int sl_SaveConfigToDb(QString key, QString value) //存储数据key和value
    {
        return SaveConfigToDb(key, value);
    }
    void sl_SetSound(bool music, bool effect)
    {
        if(music)
            SaveConfigToDb("MusicOn", "1");
        else
            SaveConfigToDb("MusicOn", "0");

        if(effect)
            SaveConfigToDb("EffectOn", "1");
        else
            SaveConfigToDb("EffectOn", "0");
    }
    //设置游戏速度
    void sl_SetSpeed(int value)
    {
        switch (value)
        {
        case 1:     //快速
            //m_pGameCore->m_nGameMessageDelay = 1000;
            //SaveConfigToDb("GameMessageDelay", "1000");
            break;
        case 2:     //慢速
            //m_pGameCore->m_nGameMessageDelay = 2000;
            //SaveConfigToDb("GameMessageDelay", "2000");
            break;
        default:    //默认
            //m_pGameCore->m_nGameMessageDelay = 1500;
            //SaveConfigToDb("GameMessageDelay", "1500");
            break;
        }
    }
    //让QML显示动态属性
    QVariant sl_ShowProperty(const char *name)
    {
        //return this->property(prop.toLocal8Bit().constData());
        return property(name);
    }



//qml 房间处理 发送信息
public slots:

    //创建一个房间
    void sl_Server_CreateGroup(qint32 playerMaxCount = 2, qint32 playerWatchingMaxCount = -1, const QString& password = "", qint32 type = 0, QVariant vData = QVariant());

    //修改房间属性
    void sl_Server_UpdateGroup(bool lock = false, bool autoClose = true);

    //退出房间
    void sl_Server_ExitGroup();

    //关闭房间,-1表示关闭所在房间,>0表示关闭房间号
    void sl_Server_CloseGroup(qint32 groupID = -1);

    //加入房间
    //JoinType:0(玩);1(观看)
    void sl_Server_JoinGroup(qint32 gid, QString password = "", bool forceJoin = false, qint32 joinType = 1, qint32 groupType = -1);

    //qml游戏准备
    void sl_Server_GetReady(qint16 duiWu);

    //踢人
    void sl_Server_Kick(qint32 socketID);

    //发送信息,type为1表示游戏中信息,为2表示房间内信息
    void sl_Server_SendMessage(QString msg, qint16 type);

    void sl_qml_ReJoinRunningGroup();
    void sl_qml_ReleaseGroupIndex(quint32 oldUserGameID, qint32 oldGroupIndex);

    //发送给服务器 游戏开始
    void sl_Server_StartGame();



    //用户强制退出,则扣分
    /*void sl_qml_TerminateGame(qint32 code)
    {
        //m_pGameCore->m_bTerminateGame = true;
        //m_pGameCore->TerminateGame(GameModel::Game_Status_Terminated, code);
        m_pGameCore->sl_OverGame(GameModel::Game_Status_Terminated, code);
    }*/



    //设置客户共享JSON数据
    //key:格式:$.xxx.yyy(对象)或$[index](数组);如果为空,则针对整个字段进行赋值(可以进行初始化);如果为$,则引用的是JSON根对象(如果不为NULL,则可以初始化)
    //data:自动识别QString,QVariantMap,QVariantList,JS对象(QJSValue)
    void sl_qml_SetClientShareExtraGameData(QVariant data, const QString &key = "", bool saveToDB = true)
    {
        /*qint32 operationID;
        do
        {
            r = intRand();
        }while(m_mapSetGameDataToNetDBFunctionCache.contains(r));*/

        m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                  << (qint16)GAME_SERVER_CLIENT
                                  << (qint16)GAME_SERVER_CLIENT_SHAREEXTRAGAMEDATA_SET
                                  << key
                                  << data
                                  << saveToDB
                                  //<< operationID
                                     ;
        m_pGameSocket->send(TRANSMIT_CLIENT_TYPE, true);
    }



public slots:
//操作网络数据存储
//dataValue是识别data的字段
//key:格式:$.xxx.yyy(对象)或$[index](数组);如果为空,则针对整个字段进行赋值(可以进行初始化);如果为$,则引用的是JSON根对象(如果不为NULL,则可以初始化)
//data:自动识别Json的QString,QVariantMap,QVariantList,JS对象(QJSValue)
//Get:返回JSON字符串
    void sl_qml_SetGameDataToNetDB(QVariant data, const QString &key = "", qint32 dataValue = 0, qint32 dataType = _Common::DataType_JSon_Info, QJSValue jsCallbackFunc = QJSValue())
    {
        qint32 operationID;
        while(m_mapSetGameDataToNetDBFunctionCache.contains(operationID = intRand()));
        m_mapSetGameDataToNetDBFunctionCache.insert(operationID, jsCallbackFunc);

        //qDebug() << "[GameManager]sl_qml_SetGameDataToNetDB:" << data << data.toMap() << key << dataValue << dataType << JSon2String(data);
        if(_Common::DataType_JSon_Info == dataType || _Common::DataType_JSon_Data == dataType)
        {
            m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                      << (qint16)GAME_SERVER_CLIENT
                                      << (qint16)GAME_SERVER_SETDATA
                                      << dataType << dataValue << key
                                      << (QVariant)JSon2String(data)
                                      << operationID
                                         ;
        }
        else
        {
            m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                      << (qint16)GAME_SERVER_CLIENT
                                      << (qint16)GAME_SERVER_SETDATA
                                      << dataType << dataValue << key
                                      << data
                                      << operationID
                                         ;
        }
        m_pGameSocket->send(TRANSMIT_DATA_TYPE, true);
    }
    void sl_qml_GetGameDataToNetDB(const QString &key = "", qint32 dataValue = 0, qint32 dataType = _Common::DataType_JSon_Info, QJSValue jsCallbackFunc = QJSValue())
    {
        qint32 operationID;
        while(m_mapGetGameDataToNetDBFunctionCache.contains(operationID = intRand()));
        m_mapGetGameDataToNetDBFunctionCache.insert(operationID, jsCallbackFunc);

        m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                  << (qint16)GAME_SERVER_CLIENT
                                  << (qint16)GAME_SERVER_GETDATA
                                  << dataType << dataValue << key
                                  << operationID
                                     ;
        m_pGameSocket->send(TRANSMIT_DATA_TYPE, true);
    }
    void sl_qml_DeleteGameDataToNetDB(qint32 dataValue = 0, qint32 dataType = _Common::DataType_JSon_Info, QJSValue jsCallbackFunc = QJSValue())
    {
        qint32 operationID;
        while(m_mapDeleteGameDataToNetDBFunctionCache.contains(operationID = intRand()));
        m_mapDeleteGameDataToNetDBFunctionCache.insert(operationID, jsCallbackFunc);

        m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                  << (qint16)GAME_SERVER_CLIENT
                                  << (qint16)GAME_SERVER_DELETEDATA
                                  << dataType << dataValue
                                  << operationID
                                     ;
        m_pGameSocket->send(TRANSMIT_DATA_TYPE, true);
    }


    void sl_qml_InsertGameDataToNetDB(QVariant data, qint32 dataValue = 0, qint32 dataType = _Common::DataType_JSon_Info, QJSValue jsCallbackFunc = QJSValue())
    {
        qint32 operationID;
        while(m_mapInsertGameDataToNetDBFunctionCache.contains(operationID = intRand()));
        m_mapInsertGameDataToNetDBFunctionCache.insert(operationID, jsCallbackFunc);

        if(_Common::DataType_JSon_Info == dataType || _Common::DataType_JSon_Data == dataType)
        {
            m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                      << (qint16)GAME_SERVER_CLIENT
                                      << (qint16)GAME_SERVER_INSERTDATA
                                      << dataType << dataValue
                                      << JSon2String(data)
                                      << operationID
                                         ;
        }
        else
        {
            m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                      << (qint16)GAME_SERVER_CLIENT
                                      << (qint16)GAME_SERVER_INSERTDATA
                                      << dataType << dataValue
                                      << data
                                      << operationID
                                         ;
        }
        m_pGameSocket->send(TRANSMIT_DATA_TYPE, true);
    }
    void sl_qml_UpdateGameDataToNetDB(QVariant data, qint32 dataValue = 0, qint32 dataType = _Common::DataType_JSon_Info, QJSValue jsCallbackFunc = QJSValue())
    {
        qint32 operationID;
        while(m_mapUpdateGameDataToNetDBFunctionCache.contains(operationID = intRand()));
        m_mapUpdateGameDataToNetDBFunctionCache.insert(operationID, jsCallbackFunc);

        if(_Common::DataType_JSon_Info == dataType || _Common::DataType_JSon_Data == dataType)
        {
            m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                      << (qint16)GAME_SERVER_CLIENT
                                      << (qint16)GAME_SERVER_UPDATEDATA
                                      << dataType << dataValue
                                      << (QVariant)JSon2String(data)
                                      << operationID
                                         ;
        }
        else
        {
            m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                      << (qint16)GAME_SERVER_CLIENT
                                      << (qint16)GAME_SERVER_UPDATEDATA
                                      << dataType << dataValue
                                      << data
                                      << operationID
                                         ;
        }
        m_pGameSocket->send(TRANSMIT_DATA_TYPE, true);
    }


    void sl_qml_QueryNetDB(QString strQuery, qint32 dataValue = 0, QJSValue jsCallbackFunc = QJSValue())
    {
        qint32 operationID;
        while(m_mapQueryNetDBFunctionCache.contains(operationID = intRand()));
        m_mapQueryNetDBFunctionCache.insert(operationID, jsCallbackFunc);

        m_pGameSocket->sendData() << (qint16)GAME_SERVER_REQUEST
                                  << (qint16)GAME_SERVER_CLIENT
                                  << (qint16)GAME_SERVER_DBQUERY
                                  << dataValue << strQuery
                                  << operationID
                                     ;
        m_pGameSocket->send(TRANSMIT_DATA_TYPE, true);
    }





public slots:
//游戏同步函数
    //给其他客户发送数据
    //targetSocketID:-1是全部客户(除自己);其他值:其他客户socketID
    void sl_qml_SendGameTransferData(QVariantMap mapTransferData, quint32 targetUserGameID = -1)
    {
        mapTransferData["__UserGameID"] = m_pUserInfo->m_GameServerUserInfo.unUserGameID;
        mapTransferData["__SocketID"] = m_pGameSocket->m_nSocketID;
        mapTransferData["__GroupIndex"] = m_pGameSocket->getGroupIndex();
        mapTransferData["__Type"] = 1;

        m_pGameSocket->sendData() << (qint16)GAME_DATA
                                  << (qint16)GAME_DATA_TRANSFER_DATA
                                  << targetUserGameID
                                  << mapTransferData
                                     ;
        m_pGameSocket->send(TRANSMIT_GAME_TYPE, true);
    }
    //发送一个数据，一帧之内保证全部转发(不管是否是半途进来的客户,包括自己)（同步数据用）
    void sl_qml_SendGameSyncData(QVariantMap mapGameData)
    {
        mapGameData["__UserGameID"] = m_pUserInfo->m_GameServerUserInfo.unUserGameID;
        mapGameData["__SocketID"] = m_pGameSocket->m_nSocketID;
        mapGameData["__GroupIndex"] = m_pGameSocket->getGroupIndex();
        mapGameData["__Type"] = 1;

        m_pGameSocket->sendData() << (qint16)GAME_DATA
                                  << (qint16)GAME_DATA_SYNC_DATA
                                  << mapGameData
                                     ;
        m_pGameSocket->send(TRANSMIT_GAME_TYPE, true);
    }
    //发送一帧的数据
    void sl_qml_SendGameFrameData(QVariantMap mapFrameData)
    {
        mapFrameData["__UserGameID"] = m_pUserInfo->m_GameServerUserInfo.unUserGameID;
        mapFrameData["__SocketID"] = m_pGameSocket->m_nSocketID;
        mapFrameData["__GroupIndex"] = m_pGameSocket->getGroupIndex();
        mapFrameData["__Type"] = 1;

        m_pGameSocket->sendData() << (qint16)GAME_DATA
                                  << (qint16)GAME_DATA_FRAME_DATA
                                  << (qint32)m_pGameSocket->m_RandomNumber.m_nRandomNumberID
                                  << (qint32)m_pGameSocket->m_RandomNumber.m_nUsePoint
                                  << (quint32)m_pGameSocket->m_ClientGroupInfo.m_unFrameIndex
                                  << mapFrameData
                                     ;
        m_pGameSocket->send(TRANSMIT_GAME_TYPE, true);
    }
    //发送所有数据给服务器备份,每一帧都要发送,此数据必须合并差异
    void sl_qml_SendGameSyncAllData(QVariantMap mapAllGameData)
    {
        //mapData["__SocketID"] = m_pGameSocket->m_nSocketID;
        qDebug() << "sl_qml_SendGameSyncAllData:" << mapAllGameData;

        m_pGameSocket->sendData() << (qint16)GAME_DATA
                                  << (qint16)GAME_DATA_SYNC_ALLDATA
                                  << (qint32)m_pGameSocket->m_RandomNumber.m_nUsePoint
                                  << mapAllGameData
                                     ;
        m_pGameSocket->send(TRANSMIT_GAME_TYPE, true);
    }

    int sl_qml_VerifyData(QVariantMap data)
    {
        qDebug() << "sl_qml_VerifyData:" << data;

        quint32 userGameID = data.value("__UserGameID", 0).toUInt();
        qint32 groupIndex = data.value("__GroupIndex", 0).toInt();;
        if(userGameID == 0 || groupIndex < 0)
            return -1;

        PlayerInfo* player = qobject_cast<PlayerInfo*>(m_mapPlayerInGroupInfo.value(groupIndex, nullptr));
        if(player == nullptr)
            return -2;

        if(player->m_nIndex <= 0 || player->m_nIndex != data.value("__GroupIndex", -1).toInt())
            return -3;

        //这个有可能是旧数据,可酌情用
        if(player->m_nSocketID <= 0 || player->m_nSocketID != data.value("__SocketID", -1).toInt())
            return 1;

        return 0;
    }



public slots:
//文件操作(目前是字符串格式,包含JSON)
    bool sl_qml_FileExists(const QString &strPathFile);

    QString sl_qml_ReadFile(const QString &strPathFile);

    int sl_qml_WriteFile(const QString &strData, const QString &strPathFile, int writeType);

    int sl_qml_DeleteFile(const QString &strPathFile);


    QString getExternalDataPath()
    {
        return g_CommonData.m_strExternalDataPath;
    }


//From QML
    void sl_qml_DebugButton(int button, QVariant v);


public:
    void NetLog(QByteArray &ba, bool s)
    {
        /*
        QFile netLog("netLogs.log");
        if(s)
            netLog.setFileName("netsLog.log");
        netLog.open(QIODevice::Append);
        netLog.write(ba.toHex());
        netLog.write("\r\n--------------------------\r\n");
        netLog.close();
        */
    }

    Q_INVOKABLE static void testStaticFn() {
        qDebug() << "testStaticFn";
    }

#if defined(Q_OS_ANDROID)   //android
    Q_INVOKABLE static void requestAllPermission()
    {

        QtAndroid::PermissionResultMap mapResult = QtAndroid::requestPermissionsSync(QStringList() <<
                                                                                     WRITE_EXTERNAL_STORAGE <<
                                                                                     ACCESS_FINE_LOCATION <<
                                                                                     ACCESS_COARSE_LOCATION <<
                                                                                     CAMERA <<
                                                                                     BLUETOOTH_ADMIN <<
                                                                                     BLUETOOTH <<
                                                                                     INSTALL_PACKAGES <<
                                                                                     RECEIVE_BOOT_COMPLETED <<
                                                                                     RECORD_AUDIO <<
                                                                                     READ_CONTACTS <<
                                                                                     READ_SMS <<
                                                                                     RECEIVE_SMS <<
                                                                                     RECEIVE_MMS <<
                                                                                     RECEIVE_WAP_PUSH
                                                                                     );

}
#endif



//属性
public:
    UserInfo* getUserInfo() const
    {
        return m_pUserInfo;
    }
    Game* getGameCore() const
    {
        return m_pGameCore;
    }
    _Platform* getPlatform() const
    {
        return m_pPlatform;
    }
    QVariantMap getGameConfig()
    {
        return m_mapGameConfig;
    }

    /*QObject* getSqliteDB() const
    {
        return m_pSqliteDB;
    }*/

    Q_INVOKABLE QObjectList getPlayerInfoList()
    {
        return m_mapPlayerInGroupInfo.values();
    }
    Q_INVOKABLE PlayerInfo* getPlayerInfo(qint32 groupIndex)
    {
        qDebug() << "getPlayerInfo" << groupIndex
                 << m_mapPlayerInGroupInfo.firstKey()
                 << m_mapPlayerInGroupInfo.first()
                 << m_mapPlayerInGroupInfo.value(groupIndex, nullptr);
        return qobject_cast<PlayerInfo*>(m_mapPlayerInGroupInfo.value(groupIndex, nullptr));
    }
    Q_INVOKABLE void showPlayersInfo()
    {
        QMap<qint32, QObject*>::const_iterator ii;
        for (ii = m_mapPlayerInGroupInfo.constBegin(); ii != m_mapPlayerInGroupInfo.constEnd(); ++ii)
        {
            qDebug() << "Client:" << ii.key() << ii.value();
        }

        qDebug() << m_mapPlayerInGroupInfo.count();
        qDebug() << m_mapPlayerInGroupInfo;
    }

    Q_INVOKABLE QMap<quint32,qint32> getDisconnectClientInfoMap()
    {
        return m_mapDisconnectClientInfo;
    }
    Q_INVOKABLE void removeAllDisconnectClient()
    {
        QMap<quint32, qint32>::const_iterator ii;
        for (ii = m_mapDisconnectClientInfo.constBegin(); ii != m_mapDisconnectClientInfo.constEnd(); ++ii)
        {
            qDebug() << "DisconnectClient:" << ii.key() << ii.value();
            sl_qml_ReleaseGroupIndex(ii.key(), ii.value());
        }
        m_mapDisconnectClientInfo.clear();
    }


//数据
public:
    //游戏设置（本地）
    QVariantMap m_mapGameConfig;   //数据库读取的配置
    Config m_ConfigFile;          //文件中读取的配置

protected:
    //QQuickWindow *pLoginWindow;
    //QQuickWindow *pRegisterWindow;
    //QQuickWindow *pGameCenterWindow;
    QQuickWindow *m_pGameWindow;
    //QQuickWindow *pDebugWindow;

    //QThread     *pGameThread;

    Game        *m_pGameCore;
    UserInfo    *m_pUserInfo;
    Sqlite      *m_pSqliteDB;
    _Platform   *m_pPlatform;

    TcpSocket   *m_pInfoSocket;
    TcpSocket   *m_pGameSocket;

    QQmlApplicationEngine *m_pAppQmlEngine;

    VersionCheck m_VersionCheck;


    // >=0(服务器), <0(客户端断开)
    qint32      m_nDisconnectCode;


    QMap<qint32, QJSValue> m_mapSetGameDataToNetDBFunctionCache;
    QMap<qint32, QJSValue> m_mapGetGameDataToNetDBFunctionCache;
    QMap<qint32, QJSValue> m_mapDeleteGameDataToNetDBFunctionCache;
    QMap<qint32, QJSValue> m_mapInsertGameDataToNetDBFunctionCache;
    QMap<qint32, QJSValue> m_mapUpdateGameDataToNetDBFunctionCache;
    QMap<qint32, QJSValue> m_mapQueryNetDBFunctionCache;

public:
    //房间里其他玩家信息(Key为GroupIndex)
    //游戏开始时，会进行随机排列并存到PlayerList中!!
    //包含本玩家本身
    QMap<qint32, QObject*> m_mapPlayerInGroupInfo;

    qint32                  m_nOldSocketID;
    QMap<quint32, qint32>   m_mapDisconnectClientInfo;
};

#endif // GAMEMANAGER_H
